package com.arpgalaxy.generator.utils;

import com.arpgalaxy.generator.entity.*;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;



/**
 * @author arpgalaxy
 * @date 2021/3/9
 * @email 13605560342@163.com
 * @description
 */
public class DataBaseUtils {

    public static Connection getConnection(DataBase db) throws Exception {
        java.util.Properties props = new java.util.Properties();
        props.put("remarksReporting","true");//获取数据库的备注信息
        props.put("user",db.getUserName());
        props.put("password",db.getPassWord());
        Class.forName(db.getDriver());//注册驱动
        return DriverManager.getConnection(db.getUrl(),props);
    }
    //获取数据库列表
    public static List<String> getSchemas(DataBase db) throws Exception {
        //1.获取元数据
        Connection connection = getConnection(db);
        DatabaseMetaData metaData = connection.getMetaData();
        //2.获取所有数据库列表
        ResultSet rs = metaData.getCatalogs();

        List<String> list = new ArrayList<>();
        while (rs.next()) {
            list.add(rs.getString(1));
        }
        rs.close();
        connection.close();
        return list;
    }

    /**
     * 获取数据库中的表和字段构造实体类
     *      Table对象
     *
     *  1.参数
     *      DataBase 数据库对象
     *  2.操作步骤
     *      1.获取连接
     *      2.获取databasemetaData
     *      3.获取当前数据库中的所有表
     *      4.获取每个表中的所有字段
     *      5.封装到java对象中即可
     */
    public static List<Table> getDbInfo(DataBase db, TypeConverter typeConverter, String dbName,Properties properties ) throws  Exception {
        //1.获取连接
        Connection connection = getConnection(db);
        //2.获取元数据
        DatabaseMetaData metaData = connection.getMetaData();
        //3.获取当前数据库中的所有表,getTables()第一个参数为数据库名，不填会获取mysql所有数据库的表
        ResultSet tables = metaData.getTables(dbName, null, null, new String[]{"TABLE"});
        int fetchSize = tables.getFetchSize();
        List<Table> list = new ArrayList<>();

        while (tables.next()) {
            Table tab = new Table();
            //i.表名
            String tableName = tables.getString("TABLE_NAME"); //bs_user  User
            String tablePrefixes = properties.getTablePrefixes();

            //ii.类名
            String className = removePrefix(tableName,tablePrefixes);
            if (className==null)continue;
            //iii.描述
            String remarks = tables.getString("REMARKS");
            //iiii.主键
            ResultSet primaryKeys = metaData.getPrimaryKeys(null, null, tableName);
            String keys = "";
            String keyTypes="";
            String keyname = null;
            while (primaryKeys.next()) {
                keyname = primaryKeys.getString("COLUMN_NAME");
                keys += keyname+",";
            }
            tab.setName(tableName);
            tab.setName2(className);
            tab.setComment(remarks);
            tab.setKey(keys);
            //处理表中的所有字段

            ResultSet columns = metaData.getColumns(null, null, tableName, null);

            List <Column> columnList = new ArrayList<>();

            while (columns.next()) {
                Column cn = new Column();
                //构造Column对象
                //列名称
                String columnName = columns.getString("COLUMN_NAME"); //user_id  userId , create_time createTime
                cn.setColumnName(columnName);
                //属性名
                String attName = StringUtils.toJavaVariableName(columnName);
                cn.setVariableName(attName);
                //java类型和数据库类型
                String dbType = columns.getString("TYPE_NAME");//VARCHAR,DATETIME

                //mysql数据库int 类型在mybatis里面没有对应的INT 转换成INTEGER and so on
                if ("INT".equals(dbType)){
                    cn.setColumnDbType("INTEGER");
                }else if("TEXT".equals(dbType)){
                    cn.setColumnDbType("VARCHAR");
                }else if("LONGTEXT".equals(dbType)){
                    cn.setColumnDbType("VARCHAR");
                }else if("DATETIME".equals(dbType)){
                    cn.setColumnDbType("DATE");
                }else{
                    cn.setColumnDbType(dbType);
                }
                String javaType = typeConverter.getTypeMap().get(dbType);
//#javatype 存入table keyType字段 用于mybatis  的xml的  parameterType字段,由于mybatis Java 类型内建的类型别名是下划线和小写的，所以做个转换，否则xml会报红，但是不影响使用
                if (tab.getKey().contains(columnName)) {
                        keyTypes += javaType.toLowerCase()+",";
                }
                cn.setJavaType(javaType);
                //备注
                String columnRemark = columns.getString("REMARKS");//VARCHAR,DATETIME
                cn.setColumnComment(columnRemark);
                //是否主键
                String pri = "";
                if(StringUtils.contains(columnName ,keys.split(","))) {
                    pri = "PRI";
                }
                cn.setColumnKey(pri);
                columnList.add(cn);
            }
//#javatype 存入table keyType字段 用于mybatis  的xml的  parameterType字段
            tab.setParameterType(keyTypes);
            columns.close();
            tab.setColumns(columnList);
            list.add(tab);
        }
        tables.close();
        connection.close();
        return list;
    }

    /**
     *
     * @param tableName
     * @param tablePrefixes
     * @return 返回null表示该表不用生成，返回字符串则表示处理后表名转化的类名。
     */
    public static String removePrefix(String tableName,String tablePrefixes) {
        String temp = tableName;  //ink_user
        for(String pf : tablePrefixes.split(",")) {
            if (tableName.startsWith(pf)){
                temp = StringUtils.removePrefix(temp,pf,true);
                //temp = user
                return StringUtils.makeAllWordFirstLetterUpperCase(temp);
            }
        }
        return null;
    }
    public static List<DataBase> getDataBaseList(Properties properties) {
        List<DataBase> dataBases = new ArrayList<>();
        String[] dbs = properties.getDbNames().split(",");
        for (String dbName : dbs){
            dataBases.add(new DataBase(
                    properties.getDbType(),
                    properties.getIP(),
                    properties.getPort(),
                    dbName,
                    properties.getUsername(),
                    properties.getPassword()
            ));
        }
        return dataBases;
    }
}

